﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Common.Utilities.Dispatcher;
using Common.Utilities;
using Common.Utilities.TextMatch;

namespace Workflows.Components.TextMining.DocumentLabels
{
    /// <summary>
    /// 
    /// </summary>
    public partial class DocumentLabelEditor : Form, IComponentEditor
    {
        /// <summary>
        /// 
        /// </summary>
        public DocumentLabelEditor()
        {
            InitializeComponent();
        }

        private void DocumentLabelEditor_Load(object sender, EventArgs e)
        {

        }

        private void btn_Browse_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dlg=new FolderBrowserDialog();
            if(dlg.ShowDialog()==System.Windows.Forms.DialogResult.OK)
            {
                this.txt_SrcFolder.Text = dlg.SelectedPath;
                DirectoryInfo dirInfo=new DirectoryInfo(dlg.SelectedPath);
                FileInfo[] fileInfos = null;
                if(!string.IsNullOrEmpty(this.txt_Extension.Text))
                {
                    fileInfos = dirInfo.GetFiles(this.txt_Extension.Text, SearchOption.TopDirectoryOnly);
                }
                else
                {
                    fileInfos = dirInfo.GetFiles("*.*", SearchOption.TopDirectoryOnly);
                }
                this.lb_Files.Items.Clear();
                if(fileInfos !=null && fileInfos.Length>0)
                {
                    foreach(FileInfo fileInfo in fileInfos)
                    {
                        this.lb_Files.Items.Add(fileInfo.Name);
                    }
                    this.lbl_FileName.Text = fileInfos[0].Name;
                }
            }
        }

        #region Implementation of IComponentEditor

        public event UpdateComponentSettings UpdateComponentSettingEvent;
        private object _ActivityNode;
        private DocumentLabelComponent _DocLabeler;

        /// <summary></summary>
        public object OwnerActivityNode
        {
            get { return _ActivityNode; }
            set { _ActivityNode = value; }
        }

        /// <summary></summary>
        public Type WorkflowComponentType
        {
            get { return typeof(DocumentLabelComponent); }
        }

        /// <summary></summary>
        public void LoadSettings(GlobalVariable[] globalVars, WorkflowComponentBase[] fromComponents, object activityNode, WorkflowComponentBase wfComponent)
        {
            this._ActivityNode = activityNode;
            this._DocLabeler = (DocumentLabelComponent) wfComponent;
            DocumentLabelInstruction instruction = (DocumentLabelInstruction) this._DocLabeler.Instruction;
            this.txt_SrcFolder.Text = instruction.SrcFolderPath;
            this.txt_Extension.Text = instruction.FileExtension;
            this.txt_EvidenceFile.Text = instruction.EvidenceFilePath;
            this.num_Threshold.Value = instruction.DistanceThreshold;
            this.num_SetenceDistance.Value = instruction.SetenceDistance;
            this.num_ParagraphDistance.Value = instruction.ParagraphDistance;
        }

        /// <summary></summary>
        public void SaveSettings()
        {
            DocumentLabelInstruction instruction = (DocumentLabelInstruction)this._DocLabeler.Instruction;
            instruction.SrcFolderPath = this.txt_SrcFolder.Text;
            instruction.FileExtension = this.txt_Extension.Text;
            instruction.EvidenceFilePath = this.txt_EvidenceFile.Text;
            instruction.DistanceThreshold = (int) this.num_Threshold.Value;
            instruction.SetenceDistance = (int) this.num_SetenceDistance.Value;
            instruction.ParagraphDistance = (int) this.num_ParagraphDistance.Value;
            this._DocLabeler.Instruction = instruction;
        }

        /// <summary></summary>
        public TestResult Test()
        {
            throw new System.NotImplementedException();
        }

        #endregion

        private void lb_Files_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(this.lb_Files.SelectedIndex>=0 && !string.IsNullOrEmpty(this.txt_SrcFolder.Text))
            {
                string filePath = Path.Combine(this.txt_SrcFolder.Text, this.lb_Files.SelectedItem.ToString());
                if(File.Exists(filePath))
                {
                    try
                    {
                        string fileContent = string.Empty;
                        if(filePath.ToLower().EndsWith(".pdf"))
                        {
                            fileContent = DocumentLabelWorker.GetPdfFileContent(filePath);
                        }
                        else
                        {
                            StreamReader reader = new StreamReader(filePath);
                            fileContent = reader.ReadToEnd();
                            reader.Close();
                        }
                        Dictionary<string, int> wordFreqs = DocumentLabelWorker.GetWordFrequencies(fileContent);
                        Dictionary<string, List<int>> wordPositions = DocumentLabelWorker.GetWordPositions(fileContent);
                        Dictionary<string, List<Range<int>>> wordRanges = DocumentLabelWorker.GetWordRanges(fileContent);
                        Dictionary<int, Range<int>> setenceRanges = DocumentLabelWorker.GetSetenceRanges(fileContent);
                        Dictionary<int, Range<int>> paragraphRanges = DocumentLabelWorker.GetParagraphRanges(fileContent);

                        this.DisplayFullText(fileContent, setenceRanges, paragraphRanges);
                        this.DisplayWordFrequencies(wordFreqs,wordPositions,wordRanges,setenceRanges,paragraphRanges);
                        this.DisplayKeywordsAndSetences(fileContent, wordFreqs, wordRanges, setenceRanges);
                    }
                    catch(Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                }
            }
        }

        #region display
        private void DisplayFullText(string fileContent, 
            Dictionary<int,Range<int>> setenceRanges,
            Dictionary<int,Range<int>> paragraphRanges)
        {
            this.rt_DocContent.Clear();
            Color color1a = Color.Red;
            Color color1b = Color.Blue;
            Color color2b = Color.White;

            foreach (int setenceID in setenceRanges.Keys)
            {
                Range<int> range = setenceRanges[setenceID];
                string setenceContent = fileContent.Substring(range.FromValue, range.ToValue - range.FromValue + 1);
                int selectionStart = this.rt_DocContent.Text.Length;
                int selectionLength = setenceContent.Length;
                this.rt_DocContent.AppendText(setenceContent);
                this.rt_DocContent.SelectionStart = selectionStart;
                this.rt_DocContent.SelectionLength = selectionLength;
                this.rt_DocContent.SelectionFont = new Font("Times New Roman", 12, FontStyle.Bold);
                this.rt_DocContent.SelectionColor = setenceID%2 == 0 ? color1a : color1b;
                this.rt_DocContent.SelectionBackColor = color2b;
            }

            //Color color2a = Color.LightGray;
            //foreach (int paragraphID in paragraphRanges.Keys)
            //{
            //    Range<int> paraRange = paragraphRanges[paragraphID];
            //    int selectionStart = paraRange.FromValue;
            //    int selectionLength = paraRange.ToValue - paraRange.FromValue + 1;
            //    this.rt_DocContent.SelectionStart = selectionStart;
            //    this.rt_DocContent.SelectionLength = selectionLength;
            //    this.rt_DocContent.SelectionBackColor = paragraphID%2 == 0 ? color2a : color2b;
            //}
        }

        private void DisplayWordFrequencies(
            Dictionary<string,int> wordFreqs,
            Dictionary<string, List<int>> wordPositions,
            Dictionary<string, List<Range<int>>> wordRanges,
            Dictionary<int, Range<int>> setenceRanges,
            Dictionary<int, Range<int>> paragraphRanges
            )
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("Word", typeof(string));
            dt.Columns.Add("Freq", typeof(int));
            dt.Columns.Add("Positions", typeof(string));
            dt.Columns.Add("Setences", typeof(string));
            dt.Columns.Add("Paragraphs", typeof(string));

            StopWordsUtil stopWordsUtil=new StopWordsUtil(StopWordsUtil.StopWordList.PubmedStopWordList);
            List<string> stopWordList = stopWordsUtil.StopWords;

            foreach (string word in wordFreqs.Keys)
            {
                if (!stopWordList.Contains(word) && word.Length >= 2)
                {
                    DataRow dr = dt.NewRow();
                    dr["Word"] = word;
                    dr["Freq"] = wordFreqs[word];
                    List<int> positions = wordPositions[word];
                    string positionValue = string.Empty;
                    foreach (int pos in positions)
                    {
                        if (positionValue.Length > 0)
                            positionValue += ",";
                        positionValue += pos.ToString();
                    }
                    dr["Positions"] = positionValue;
                    List<int> setenceIDs = new List<int>();
                    List<Range<int>> ranges = wordRanges[word];
                    foreach (int setenceID in setenceRanges.Keys)
                    {
                        bool containsWord = false;
                        Range<int> setenceRange = setenceRanges[setenceID];
                        foreach (Range<int> range in ranges)
                        {
                            if (range.OverlapWith(setenceRange))
                            {
                                containsWord = true;
                                break;
                            }
                        }
                        if (containsWord)
                            setenceIDs.Add(setenceID);
                    }
                    string setencePositionValue = string.Empty;
                    foreach (int setenceID in setenceIDs)
                    {
                        if (setencePositionValue.Length > 0)
                            setencePositionValue += ",";
                        setencePositionValue += setenceID.ToString();
                    }
                    dr["Setences"] = setencePositionValue;
                    List<int> paragraphIDs = new List<int>();
                    foreach (int paragraphID in paragraphRanges.Keys)
                    {
                        bool containsWord = false;
                        Range<int> paragraphRange = paragraphRanges[paragraphID];
                        foreach (Range<int> range in ranges)
                        {
                            if (range.OverlapWith(paragraphRange))
                            {
                                containsWord = true;
                                break;
                            }
                        }
                        if (containsWord)
                            paragraphIDs.Add(paragraphID);
                    }
                    string paragraphPositionValue = string.Empty;
                    foreach (int paragraphID in paragraphIDs)
                    {
                        if (paragraphPositionValue.Length > 0)
                            paragraphPositionValue += ",";
                        paragraphPositionValue += paragraphID.ToString();
                    }
                    dr["Paragraphs"] = paragraphPositionValue;

                    dt.Rows.Add(dr);
                }
            }

            this.dv_WordFreq.DataSource = dt;
            this.dv_WordFreq.Refresh();
        }

        private void DisplayKeywordsAndSetences(
            string fileContent,
            Dictionary<string,int> wordFreqs,
            Dictionary<string,List<Range<int>>> wordRanges,
            Dictionary<int,Range<int>> setenceRanges)
        {
            Dictionary<string, Dictionary<string, double>> interactions =
                DocumentLabelWorker.CalculateWordInteractions(
                    wordFreqs, wordRanges, setenceRanges);
            Dictionary<string, int> keywords = new Dictionary<string, int>();
            foreach(string fromWord in interactions.Keys)
            {
                if(interactions[fromWord].Count>0)
                {
                    if(!keywords.ContainsKey(fromWord))
                        keywords.Add(fromWord, interactions[fromWord].Count+wordFreqs[fromWord]);
                    else
                        keywords[fromWord] = keywords[fromWord] + interactions[fromWord].Count;
                    foreach (string toWord in interactions[fromWord].Keys)
                    {
                        if (!keywords.ContainsKey(toWord))
                            keywords.Add(toWord, wordFreqs[toWord] + 1);
                        else
                            keywords[toWord] = keywords[toWord] + 1;
                    }
                }
            }
            DataTable dtKeywords=new DataTable();
            dtKeywords.Columns.Add("Keyword", typeof (string));
            dtKeywords.Columns.Add("Score", typeof (int));
            foreach(string keyword in keywords.Keys)
            {
                DataRow drKeyword = dtKeywords.NewRow();
                drKeyword["Keyword"] = keyword;
                drKeyword["Score"] = keywords[keyword];
                dtKeywords.Rows.Add(drKeyword);
            }
            this.dv_Keywords.DataSource = dtKeywords;
            this.dv_Keywords.Refresh();

            Dictionary<int, double> keySetences =
                DocumentLabelWorker.GetKeySetences(keywords, wordRanges, setenceRanges, 100, 25);
            //double maxScore = 0;
            //int bestSetenceID = 0;
            //foreach(int setenceID in keySetences.Keys)
            //{
            //    if(keySetences[setenceID]>maxScore)
            //    {
            //        bestSetenceID = setenceID;
            //        maxScore = keySetences[setenceID];
            //    }
            //}
            
            DataTable dtSetence=new DataTable();
            dtSetence.Columns.Add("SetenceID", typeof (int));
            dtSetence.Columns.Add("Score", typeof (double));
            dtSetence.Columns.Add("Setence", typeof (string));
            if(keySetences !=null && keySetences.Count>0)
            {
                foreach(int setenceID in keySetences.Keys)
                {
                    DataRow drSetence = dtSetence.NewRow();
                    drSetence["SetenceID"] = setenceID;
                    Range<int> range = setenceRanges[setenceID];
                    string setence = fileContent.Substring(range.FromValue, range.ToValue - range.FromValue + 1);
                    drSetence["Score"] = keySetences[setenceID];
                    drSetence["Setence"] = setence;
                    dtSetence.Rows.Add(drSetence);
                }
            }
            this.dv_KeySetence.DataSource = dtSetence;
            this.dv_KeySetence.Refresh();
        }
        #endregion
    }
}
